package com.xinqi.modules.stats.score.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xinqi.common.core.constant.Constants;
import com.xinqi.common.core.enums.TotalScoreTypeEnum;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.course.clazz.client.ClassClient;
import com.xinqi.modules.course.clazz.dto.rsp.ClassResultDTO;
import com.xinqi.modules.course.course.client.RemoteCourseClient;
import com.xinqi.modules.course.course.dto.rsp.CourseResultDTO;
import com.xinqi.modules.stats.score.convert.CourseTotalScoreConvert;
import com.xinqi.modules.stats.score.convert.CourseTotalScoreTypeConvert;
import com.xinqi.modules.stats.score.domain.CourseTotalScoreContentEntity;
import com.xinqi.modules.stats.score.domain.CourseTotalScoreEntity;
import com.xinqi.modules.stats.score.domain.CourseTotalScoreTypeEntity;
import com.xinqi.modules.stats.score.dto.req.*;
import com.xinqi.modules.stats.score.dto.rsp.*;
import com.xinqi.modules.stats.score.mapper.CourseTotalScoreContentSonMapper;
import com.xinqi.modules.stats.score.mapper.CourseTotalScoreMapper;
import com.xinqi.modules.stats.score.service.CourseTotalScoreConfigService;
import com.xinqi.modules.stats.score.service.CourseTotalScoreContentService;
import com.xinqi.modules.stats.score.service.CourseTotalScoreService;
import com.xinqi.modules.stats.score.service.CourseTotalScoreTypeService;
import com.xinqi.modules.stats.utils.ExcelUtil;
import com.xinqi.modules.stats.utils.MathUtils;
import lombok.RequiredArgsConstructor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 成绩管理总成绩主表服务层实现
 *
 * @author: system
 * @date: 2023/03/26
 */
@Service("courseTotalScoreService")
@RequiredArgsConstructor
public class CourseTotalScoreServiceImpl extends BaseServiceImpl<CourseTotalScoreMapper, CourseTotalScoreEntity> implements CourseTotalScoreService {

    private final CourseTotalScoreConvert courseTotalScoreConvert;

    private final CourseTotalScoreTypeConvert courseTotalScoreTypeConvert;

    private final CourseTotalScoreContentService courseTotalScoreContentService;

    private final CourseTotalScoreMapper courseTotalScoreMapper;

    private final CourseTotalScoreContentSonMapper courseTotalScoreContentSonMapper;

    private final CourseTotalScoreConfigService courseTotalScoreConfigService;

    private final CourseTotalScoreTypeService courseTotalScoreTypeService;

    private final ClassClient classClient;

    private final RemoteCourseClient remoteCourseClient;

    /**
     * 获取总成绩设置
     */
    @Override
    public CourseTotalScoreResultDTO findCourseTotalScore(CourseTotalScoreClassDTO dto) {
        if (dto.getType() == null) {
            dto.setType(TotalScoreTypeEnum.ALL_SCORE.getCode());
        }
        if (dto.getType().equals(TotalScoreTypeEnum.ALL_SCORE.getCode())) {
            LambdaQueryWrapper<CourseTotalScoreEntity> wrapper = Queries.lambda();
            wrapper.eq(CourseTotalScoreEntity::getClassId, dto.getClassId());
            CourseTotalScoreResultDTO result = this.baseMapper.selectDtoOne(wrapper, courseTotalScoreConvert::convert);
            return result;
        } else {
            LambdaQueryWrapper<CourseTotalScoreTypeEntity> wrapper = Queries.lambda();
            wrapper.eq(CourseTotalScoreTypeEntity::getClassId, dto.getClassId());
            wrapper.eq(CourseTotalScoreTypeEntity::getType, dto.getType());
            CourseTotalScoreTypeEntity entity = courseTotalScoreTypeService.getBaseMapper().selectOne(wrapper);
            return courseTotalScoreTypeConvert.converts(entity);
        }

    }

    /**
     * 设置总成绩
     */
    @Override
    public boolean setCourseTotalScore(CourseTotalScoreCreateDTO dto) {
        if (TotalScoreTypeEnum.ALL_SCORE.getCode().equals(dto.getType())) {
            // 查询是否有原数据
            LambdaQueryWrapper<CourseTotalScoreEntity> wrapper = Queries.lambda();
            wrapper.eq(CourseTotalScoreEntity::getClassId, dto.getClassId());
            CourseTotalScoreResultDTO resultDTO = this.baseMapper.selectDtoOne(wrapper, courseTotalScoreConvert::convert);
            if (resultDTO == null) {
                return this.save(courseTotalScoreConvert.create(dto));
            } else {
                CourseTotalScoreEntity entity = courseTotalScoreConvert.update(dto);
                entity.setId(resultDTO.getId());
                return this.updateById(entity);
            }
        } else {
            CourseTotalScoreTypeCreateDTO scoreType = new CourseTotalScoreTypeCreateDTO();
            scoreType.setClassId(dto.getClassId());
            scoreType.setType(dto.getType());
            scoreType.setIsUserLevelShow(dto.getIsUserLevelShow());
            return courseTotalScoreTypeService.setCourseTotalScoreType(scoreType);
        }
    }

    /**
     * APP总成绩: 首页顶部统计信息-老师端
     */
    @Override
    public TotalScoreStudentScoreTeacherDTO main(CourseTotalScoreClassDTO dto) {
        TotalScoreStudentScoreTeacherDTO studentScore = new TotalScoreStudentScoreTeacherDTO();
        // 获取总成绩总配置
        LambdaQueryWrapper<CourseTotalScoreEntity> wrapper = Queries.lambda();
        wrapper.eq(CourseTotalScoreEntity::getClassId, dto.getClassId());
        CourseTotalScoreResultDTO resultDTO = courseTotalScoreMapper.selectDtoOne(wrapper, courseTotalScoreConvert::convert);
        if (Objects.isNull(resultDTO) || Objects.isNull(resultDTO.getFullScore())) {
            return null;
        }

        // 获取成绩加权项
        LambdaQueryWrapper<CourseTotalScoreContentEntity> wrapperContent = Queries.lambda();
        wrapperContent.eq(CourseTotalScoreContentEntity::getClassId, dto.getClassId());
        wrapperContent.eq(CourseTotalScoreContentEntity::getStatus, 1);
        List<CourseTotalScoreContentEntity> contentS = courseTotalScoreContentService.list(wrapperContent);
        if (Objects.isNull(contentS) || contentS.size() == 0) {
            return null;
        }

        studentScore.setFullScore(MathUtils.stripTrailingZeros(resultDTO.getFullScore(), 1));
        studentScore.setIsUserLevelShow(resultDTO.getIsUserLevelShow());
        studentScore.setIsShowStudentRule(resultDTO.getIsShowStudentRule());
        studentScore.setIsShowStudent(resultDTO.getIsShowStudent() == null ? 1 : resultDTO.getIsShowStudent());

        // 获取总成绩最高分最低分平均分
        CourseTotalScoreAllScoreResultDTO allScoreResultDTO = courseTotalScoreContentSonMapper.findTotalScoreAllScoreInfo(dto.getClassId());
        if (Objects.isNull(allScoreResultDTO)) {
            return null;
        }
        studentScore.setMaxScore(MathUtils.stripTrailingZeros(allScoreResultDTO.getMaxScore(), 1));
        studentScore.setMinScore(MathUtils.stripTrailingZeros(allScoreResultDTO.getMinScore(), 1));
        studentScore.setAvgScore(MathUtils.stripTrailingZeros(allScoreResultDTO.getAvgScore(), 1));

        // 获取等级分制
        CourseTotalScoreConfigClassDTO config = new CourseTotalScoreConfigClassDTO();
        config.setClassId(dto.getClassId());
        config.setType(TotalScoreTypeEnum.ALL_SCORE.getCode());
        List<CourseTotalScoreConfigResultDTO> list = this.courseTotalScoreConfigService.findCourseTotalScoreConfig(config);
        studentScore.setConfigList(list);

        // 计算等级分制
        studentScore.setFullGrade(checkTypeGrade(list, studentScore.getFullScore(), studentScore.getFullScore()));
        studentScore.setMaxGrade(checkTypeGrade(list, studentScore.getFullScore(), studentScore.getMaxScore()));
        studentScore.setMinGrade(checkTypeGrade(list, studentScore.getFullScore(), studentScore.getMinScore()));
        studentScore.setAvgGrade(checkTypeGrade(list, studentScore.getFullScore(), studentScore.getAvgScore()));

        return studentScore;
    }

    /**
     * 总成绩：APP学生加权成绩列表查询
     */
    @Override
    public List<Map<String, Object>> studentTotalAPPScoreList(CourseTotalScoreClassDTO dto) {

        // 获取总成绩总配置
        LambdaQueryWrapper<CourseTotalScoreEntity> wrapper = Queries.lambda();
        wrapper.eq(CourseTotalScoreEntity::getClassId, dto.getClassId());
        CourseTotalScoreResultDTO resultDTO = courseTotalScoreMapper.selectDtoOne(wrapper, courseTotalScoreConvert::convert);
        if (resultDTO == null || resultDTO.getFullScore() == null) {
            return null;
        }

        // 获取等级分制
        CourseTotalScoreConfigClassDTO config = new CourseTotalScoreConfigClassDTO();
        config.setClassId(dto.getClassId());
        List<CourseTotalScoreConfigResultDTO> configList = this.courseTotalScoreConfigService.initCourseTotalScoreConfig(config);

        // 查询加权的数据
        CourseTotalScoreClassDTO classDTO = new CourseTotalScoreClassDTO();
        classDTO.setClassId(dto.getClassId());
        List<CourseTotalScoreContentResultDTO> list = this.courseTotalScoreContentService.findOpenTotalScoreContentContainSon(classDTO);
        List<CourseContentTotalTipDTO> tipList = list.stream().map(v -> {
            CourseContentTotalTipDTO tipDTO = new CourseContentTotalTipDTO();
            tipDTO.setClassId(v.getClassId());
            tipDTO.setType(v.getType());
            tipDTO.setName(v.getName());
            tipDTO.setWeight(v.getWeight());
            tipDTO.setUnionStudentScore("studentScore" + v.getType());
            tipDTO.setAvgScore(MathUtils.stripTrailingZeros(tipDTO.getAvgScore(), 1));
            tipDTO.setScore(MathUtils.stripTrailingZeros(tipDTO.getScore(), 1));
            return tipDTO;
        }).collect(Collectors.toList());

        // 查询学生各分类成绩 计算学生总成绩
        CourseContentTotalScoreCalDTO calDTO = new CourseContentTotalScoreCalDTO();
        calDTO.setClassId(dto.getClassId());
        calDTO.setList(tipList);
        calDTO.setGroupId(dto.getGroupId());
        calDTO.setKeyWords(dto.getKeyWords());
        List<Map<String, Object>> studentList = this.baseMapper.studentAllTotalScoreList(calDTO);
        studentList.forEach(item -> {
            item.put("studentId", item.get("student_id"));
            BigDecimal studentScore = new BigDecimal(0);
            item.put("studentScore", studentScore);
            tipList.forEach(tipItem -> {
                if (!Objects.equals(Constants.DOUBLE_REDUCE, item.get(tipItem.getUnionStudentScore()))) {
                    BigDecimal oldScore = new BigDecimal(item.get("studentScore").toString());
                    item.put("studentScore", oldScore.add(new BigDecimal(item.get(tipItem.getUnionStudentScore()).toString())));
                }
            });
            item.put("isUserLevelShow", resultDTO.getIsUserLevelShow());
            item.put("grade", this.checkTypeGrade(configList, resultDTO.getFullScore(), new BigDecimal(item.get("studentScore").toString())));
        });
        return studentList;
    }

    /**
     * 总成绩：WEB学生加权成绩列表查询
     */
    @Override
    public CourseContentTotalScorePCResultDTO studentTotalPCScoreList(CourseTotalScoreClassDTO dto) {
        // 查询加权的数据
        CourseTotalScoreClassDTO classDTO = new CourseTotalScoreClassDTO();
        classDTO.setClassId(dto.getClassId());
        List<CourseTotalScoreContentResultDTO> list = this.courseTotalScoreContentService.findOpenTotalScoreContentContainSon(classDTO);
        List<CourseContentTotalTipDTO> tipList = list.stream().map(v -> {
            CourseContentTotalTipDTO tipDTO = new CourseContentTotalTipDTO();
            tipDTO.setClassId(v.getClassId());
            tipDTO.setType(v.getType());
            tipDTO.setName(v.getName());
            tipDTO.setWeight(v.getWeight());
            tipDTO.setUnionStudentScore("studentScore" + v.getType());
            tipDTO.setAvgScore(MathUtils.stripTrailingZeros(tipDTO.getAvgScore(), 1));
            tipDTO.setScore(MathUtils.stripTrailingZeros(tipDTO.getScore(), 1));
            return tipDTO;
        }).collect(Collectors.toList());

        if (tipList.size() == 0) {
            return null;
        }

        // 查询学生列表
        CourseContentTotalScoreCalDTO calDTO = new CourseContentTotalScoreCalDTO();
        calDTO.setClassId(dto.getClassId());
        calDTO.setList(tipList);

        // 前端默认传0 解析为空
        if (dto.getGroupId() != null && dto.getGroupId() == 0) {
            dto.setGroupId(null);
        }
        calDTO.setGroupId(dto.getGroupId());

        calDTO.setKeyWords(dto.getKeyWords());
        List<Map<String, Object>> studentList = this.baseMapper.studentAllTotalScoreList(calDTO);
        studentList.forEach(item -> {
            BigDecimal totalScore = new BigDecimal(0);
            item.put("totalScore", totalScore);
            tipList.forEach(tipItem -> {
                if (!Objects.equals(Constants.DOUBLE_REDUCE, item.get(tipItem.getUnionStudentScore()))) {
                    BigDecimal oldScore = new BigDecimal(item.get("totalScore").toString());
                    item.put("totalScore", oldScore.add(new BigDecimal(item.get(tipItem.getUnionStudentScore()).toString())));
                }
            });

        });
        //返回对像赋值
        CourseContentTotalScorePCResultDTO resultDTO = new CourseContentTotalScorePCResultDTO();
        resultDTO.setTipList(tipList);
        resultDTO.setStudentList(studentList);
        return resultDTO;
    }

    /**
     * 校验等级值
     */
    private String checkTypeGrade(List<CourseTotalScoreConfigResultDTO> list, BigDecimal score, BigDecimal studentScore) {
        String grade = "";
        for (int i = 0; i < list.size(); i++) {
            CourseTotalScoreConfigResultDTO item = list.get(i);
            BigDecimal maxScore = score.multiply(new BigDecimal(item.getMax())).divide(new BigDecimal(100), BigDecimal.ROUND_DOWN);
            BigDecimal minScore = score.multiply(new BigDecimal(item.getMin())).divide(new BigDecimal(100), BigDecimal.ROUND_DOWN);
            if (i == 0) {
                if (studentScore.compareTo(minScore) > 0 && studentScore.compareTo(maxScore) <= 0) {
                    grade = item.getGrade();
                }
            } else {
                if (studentScore.compareTo(minScore) >= 0 && studentScore.compareTo(maxScore) <= 0) {
                    grade = item.getGrade();
                }
            }
        }
        return grade;
    }

    /**
     * 总成绩下载
     */
    @Override
    public void downTotalExcel(CourseTotalScoreStudentQueryDTO dto, HttpServletResponse response) {
        // 查询加权的数据
        CourseTotalScoreClassDTO classDTO = new CourseTotalScoreClassDTO();
        classDTO.setClassId(dto.getClassId());
        List<CourseTotalScoreContentResultDTO> list = this.courseTotalScoreContentService.findOpenTotalScoreContentContainSon(classDTO);
        List<CourseContentTotalTipDTO> tipList = list.stream().map(v -> {
            CourseContentTotalTipDTO tipDTO = new CourseContentTotalTipDTO();
            tipDTO.setClassId(v.getClassId());
            tipDTO.setType(v.getType());
            tipDTO.setName(v.getName());
            tipDTO.setWeight(v.getWeight());
            tipDTO.setUnionStudentScore("studentScore" + v.getType());
            tipDTO.setAvgScore(MathUtils.stripTrailingZeros(tipDTO.getAvgScore(), 1));
            tipDTO.setScore(MathUtils.stripTrailingZeros(tipDTO.getScore(), 1));
            return tipDTO;
        }).collect(Collectors.toList());
        // excel表头
        List<Map<String, Object>> titleList = list.stream().map(v -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("title", v.getName());
            map.put("unionValue", "studentScore" + v.getType());
            return map;
        }).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>();
        map.put("title", "最终成绩");
        map.put("unionValue", "totalScore");
        titleList.add(map);

        // 查询学生列表
        CourseContentTotalScoreCalDTO calDTO = new CourseContentTotalScoreCalDTO();
        calDTO.setClassId(dto.getClassId());
        calDTO.setList(tipList);
        calDTO.setKeyWords(dto.getKeyWords());
        List<Map<String, Object>> studentList = this.baseMapper.studentAllTotalScoreList(calDTO);
        studentList.forEach(item -> {
            BigDecimal totalScore = new BigDecimal(0);
            item.put("totalScore", totalScore);
            tipList.forEach(tipItem -> {
                if (!Objects.equals(Constants.DOUBLE_REDUCE, item.get(tipItem.getUnionStudentScore()))) {
                    BigDecimal oldScore = new BigDecimal(item.get("totalScore").toString());
                    item.put("totalScore", oldScore.add(new BigDecimal(item.get(tipItem.getUnionStudentScore()).toString())));
                }
            });

        });
        String description = "总成绩";
        ClassResultDTO classDto = classClient.findClass(dto.getClassId()).getData();
        CourseResultDTO courseDto = remoteCourseClient.findCourse(classDto.getCourseId()).getData();
        description = courseDto.getCourseName() + " " + classDto.getName() + " " + description;

        XSSFWorkbook workbook = ExcelUtil.createExcel("成绩管理", description, titleList, studentList);
        ExcelUtil.downLoadExcel("总成绩", response, workbook);
    }

}
